﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef G_PROPERTYINSTANCE_SETTING_H
#define G_PROPERTYINSTANCE_SETTING_H
#pragma once

#include "QtCommonWidget.h"
#include <QString>
#include <qvariant.h>
#include <qstringlist.h>

#include <stdint.h>
#include <vector>
#include <memory>

namespace PropertyWidget
{

    // TableView.ItemDelegate选项
    enum GEditStyle
    {
        esNone,                     // 不能编辑
        esSimple,                   // 默认编辑框,根据数据类型创建编辑方式
        esPlainEdit,                // 多行编辑框
        esLineEdit,                 // 单行编辑框
        esPlainEllipsis,            // 省略号按钮
        esLineEllipsis,             // 省略号按钮，单行编辑
        esMultiButton,              // 多个按钮
        esBool,                     // 布尔类型的格子
        esMonthCalendar,            // 日期选择框
        esImage,                    // 图片
        esVectorGraph,              // 矢量图
        esFontList,                 // 字体选择框
        esColorList,                // 颜色选择列表
        esLineWidthList,            // 线框选择列表
        esUpDown,                   // 增量设置框
        esDropDown,                 // 下拉选择框
        esTreeView,                 // 树形框
        esDropDownWindow,           // 下拉的浮动窗体
        esDropDownWindowEllipsis,   // 下拉的浮动窗体, button的样式为三个点
        esDropDownWindowNone        // 下拉的浮动窗体, 不显示button
    };

    // GridSetting选项
    enum GLDGridSettingEditStyle
    {
        gesAuto,
        gesEdit,
        gesDropDownList,
        gesDropDown,
        gesEllipsisReadOnly,
        gesEllipsis,
        gesDateTimePicker,
        gesTreeView,
        gesCheckBox,
        gesDropDownWindowReadOnly,
        gesSpin,
        gesDropDownWindow,
        gesLineEdit
    };

    class CPropertyGroupItem;
    /*!
    *@class CPropertyItem
    *@brief 属性项类，定义了单个属性项需要包含的主要信息(数据和界面)
    *
    */
    class QT_COMMON_WIDGET_EXPORT CPropertyItem
    {
        friend class CPropertyGroupItem;
    public:
        CPropertyItem(int uniqueID, const QString& name, const QString& description, const QVariant& value, int index, bool isEnable = true,
            GEditStyle editStyle = esSimple, bool bCanBindToOther = false, CPropertyGroupItem* pGroupItem = 0);
        virtual ~CPropertyItem();

    public:
        /*!
        *@brief      设置属性名称
        *@param [in] const QString & name
        *@return     void
        */
        void SetName(const QString& name);
        /*!
        *@brief      获取属性名称
        *@return     QT_NAMESPACE::QString
        */
        const QString& GetName() const;
        /*!
        *@brief      设置原始属性参数名称
        *@param [in] const QString & name
        *@return     void
        */
        void SetOriginParamName(const QString& name);
        /*!
        *@brief      获取原始属性参数名称
        *@return     QT_NAMESPACE::QString
        */
        const QString& GetOriginParamName() const;
        /*!
        *@brief      设置属性显示名称
        *@param [in] const QString & name
        *@return     void
        */
        /*!
        *@brief      获取索引，不稳定(插入、删除分组会改变后续分组的索引)
        *@return     int
        */
        int Index() const;
        /*!
        *@brief      获取唯一标识
        *@return     int
        */
        int UniqueID() const;
        /*!
        *@brief      设置属性值
        *@param [in] const QVariant & value
        *@return     bool
        */
        bool SetValue(const QVariant& value);
        /*!
        *@brief      获取属性值
        *@return     QT_NAMESPACE::QVariant
        */
        const QVariant& GetValue() const;
        /*!
        *@brief      设置属性描述
        *@param [in] const QString & description
        *@return     void
        */
        void SetDescription(const QString& description);
        /*!
        *@brief      获取属性描述
        *@return     QT_NAMESPACE::QString
        */
        QString GetDescription() const;
        /*!
        *@brief      设置属性编辑的控件类型
        *@param [in] GEditStyle editStyle
        *@return     void
        */
        void SetEditStyle(GEditStyle editStyle);
        /*!
        *@brief      获取属性编辑的控件类型
        *@return     GEditStyle
        */
        GEditStyle GetEditStyle() const;
        /*!
        *@brief      获取当前属性所属的属性组
        *@return     CPropertyGroupItem *
        */
        CPropertyGroupItem* GetGroupItem() const;
        /*!
        *@brief      设置控件的编辑状态
        *@param [in] bool bIsReadOnly
        *@return     void
        */
        void SetEnable(bool bIsEnable);
        /*!
        *@brief      获取属性的编辑状态
        *@return     bool
        */
        bool IsEnable() const;
        /*!
        *@brief      设置控件的手动输入限制设置
        *@param [in] bool bIsReadOnly
        *@return     void
        */
        void SetManualInputModifiable(bool bIsModifiable);
        /*!
        *@brief      获取手动输入限制设置
        *@return     bool
        */
        bool IsManualInputModifiable() const;

        /*!
        *@brief      当属性的编辑控件为下拉列表时为之设置下拉列表值
        *@param [in] const QStringList & rItems
        *@return     void
        */
        void SetComboboxItems(const QStringList& rItems);
        /*!
        *@brief      获取下拉列表控件的下拉列表选项值
        *@return     QT_NAMESPACE::QStringList
        */
        const QStringList& GetComboboxItems()const;

        /*!
        *@brief      设置控件的多值状态
        *@param [in] bool bIsReadOnly
        *@return     void
        */
        void SetIsMultiValue(bool isMultiVal);
        /*!
        *@brief      获取属性的多值状态
        *@return     bool
        */
        bool IsMultiValue() const;

        void SetCanBindToOther(bool bCanBind);
        bool CanBind();

    private:
        //设置属性所属的分组
        void SetGroupItem(CPropertyGroupItem *pGroupItem);
        //设置属性的在分组中的索引
        void SetIndex(int index);
        const QString GetMultiValueString() const { return QString::fromStdWString(L"*多种*"); }

    private:
        QString     m_name;       //属性名称
        QString     m_originParamName;  //属性参数名称
        QVariant    m_value;      //属性的值
        QString     m_itemDesp;   //描述
        GEditStyle  m_editStyle;  //编辑样式
        int         m_index;      //在属性组中的索引
        int         m_uniqueID;   //唯一标识
        bool        m_isEnable;   //是否为只读
        bool        m_isModifiable; //手动输入限制设置(列表框控件默认不允许手动输入修改)
        QStringList m_comboboxItems;//Combobox下拉列表的值
        bool        m_bCanBind;     //是否可绑定
        bool        m_isMultiVal;   //是否多值

        //所在的分组  
        CPropertyGroupItem * m_groupItem; 
    };

    /*!
    *@class CPropertyGroupItem
    *@brief 属性项组类，定义了属性项单个分组需要包含的基本信息
    *
    */
    class QT_COMMON_WIDGET_EXPORT CPropertyGroupItem: public CPropertyItem
    {
        friend class CPropertyInstanceSetting;
    public:
        CPropertyGroupItem(int groupIndex, int uniqueID, const QString& name, const QString& desp);
        virtual ~CPropertyGroupItem();
    private:
        CPropertyGroupItem(const CPropertyGroupItem&);
        CPropertyGroupItem& operator=(const CPropertyGroupItem&);

    public:
        /*!
        *@brief      获取当前分组的索引，不稳定(插入、删除分组会改变后续分组的索引)
        *@param [in] int index
        *@return     void
        */
        int GetGroupIndex() const;

        /*!
        *@brief      在指定索引处插入新的属性，并返回新创建的属性
        *@param [in] int index                    待插入的位置
        *@param [in] int uniqueID             唯一标识
        *@param [in] const QString & name         新属性的名称
        *@param [in] const QString & description  新属性的描述
        *@param [in] const QVariant& value        初始值
        *@param [in] bool bIsReadOnly              是否可编辑
        *@param [in] GEditStyle editStyle         新属性的编辑样式
        *@return     CPropertyItem*                新属性
        */
        CPropertyItem* InsertPropertyItem(int index, int uniqueID, const QString& name, const QString& description, 
            const QVariant& value, bool isEnable, GEditStyle editStyle, bool bCanbeBind = false);
        /*!
        *@brief      添加属性(追加到现有属性后面)
        *@param [in] int uniqueID             唯一标识
        *@param [in] const QString & name         新属性的名称
        *@param [in] const QString & description  新属性的描述
        *@param [in] const QVariant& value        初始值
        *@param [in] bool bIsReadOnly              是否可编辑
        *@param [in] GEditStyle editStyle         新属性的编辑样式
        *@return     CPropertyItem*                新属性
        */
        CPropertyItem* AddPropertyItem(int uniqueID, const QString& name, const QString& description, 
            const QVariant& value, bool isEnable, GEditStyle editStyle, bool bCanbeBind = false);
        /*!
        *@brief      获取索引处的属性
        *@param [in] int index
        *@return     CPropertyItem*
        */
        CPropertyItem* Item(int index) const;
        /*!
        *@brief      获取满足名称条件的属性，注意重复的情况下返回第一个查询到的属性
        *@param [in] const QString & name
        *@return     CPropertyItem*
        */
        CPropertyItem* Item(const QString& name);
        /*!
        *@brief      获取uniqueID的属性
        *@param [in] int uniqueID
        *@return     CPropertyItem*
        */
        CPropertyItem* GetItem(int uniqueID) const;

        /*!
        *@brief      移除索引处的属性，后续的属性的索引会前移一位
        *@param [in] int index
        *@return     bool
        */
        bool RemoveItem(int index);
        /*!
        *@brief      移除满足名称条件的属性，存在重复的时返回第一个查询到的属性，后续的属性的索引会前移一位
        *@param [in] const QString & name
        *@return     bool
        */
        bool RemoveItem(const QString& name);

        /*!
        *@brief      获取当前分组属性的数目
        *@return     int
        */
        int PropertyItemsCount() const;
        /*!
        *@brief      释放全部的属性对象
        *@return     void
        */
        void RemoveAllPropertyItems();

    private:
        //设置当前分组的索引
        void SetGroupIndex(int index);
    private:
        //编号
        int  m_groupIndex;
        //子属性
        std::vector<std::unique_ptr<CPropertyItem>> m_propertyItems;
    };

    /*!
    *@class CPropertyItemBase
    *@brief 属性项基类，定义了属性项的最基本信息
    *
    */
    class QT_COMMON_WIDGET_EXPORT CPropertyInstanceSetting
    {
        friend class CPropertyWidget;

    public:
        CPropertyInstanceSetting();
        ~CPropertyInstanceSetting();
    private:
        CPropertyInstanceSetting(const CPropertyInstanceSetting&);
        CPropertyInstanceSetting& operator=(const CPropertyInstanceSetting&);

    public:
        /*!
        *@brief      插入属性分组项
        *@param [in] int index                插入处的索引
        *@param [in] int uniqueID         唯一标识
        *@param [in] const QString & name     新分组的名称
        *@param [in] const QString & description    新分组的描述
        *@return     CPropertyGroupItem*       新创建的分组
        */
        CPropertyGroupItem* InsertPropertyGroupItem(int index, int uniqueID, const QString& name, const QString& description);
        /*!
        *@brief      追加属性分组
        *@param [in] int uniqueID         唯一标识
        *@param [in] const QString & name     新分组的名称
        *@param [in] const QString & description    新分组的描述
        *@return     CPropertyGroupItem*       新创建的分组
        */
        CPropertyGroupItem* AddPropertyGroupItem(int uniqueID, const QString& name, const QString& description);
        /*!
        *@brief      根据索引获取属性分组
        *@param [in] int index                
        *@return     CPropertyGroupItem*
        */
        CPropertyGroupItem* PropertyGroupItem(int index) const;
        /*!
        *@brief      根据名称获取属性分组
        *@param [in] const QString & name
        *@return     CPropertyGroupItem*
        */
        CPropertyGroupItem* PropertyGroupItem(const QString& name) const;
        /*!
        *@brief      根据唯一标识获取属性组
        *@param [in] int uniqueID
        *@return CPropertyGroupItem*
        */
        CPropertyGroupItem* GetPropertyGroupItemByUniqueID(int uniqueID) const;
        /*!
        *@brief      移除指定属性分组中的指定属性
        *@param [in] int groupIndex
        *@param [in] int nPropertyIndex
        *@return     bool
        */
        bool RemovePropertyItem(int groupIndex, int nPropertyIndex);
        /*!
        *@brief      获取指定分组中的属性
        *@param [in] int groupIndex
        *@param [in] int nPropertyIndex
        *@return     CPropertyItem*
        */
        const CPropertyItem* GetPropertyItem(int groupIndex, int nPropertyIndex) const;
        /*!
        *@brief      通过唯一标识获取属性
        *@param [in] int uniqueID
        *@return CPropertyItem*
        */
        CPropertyItem* GetPropertyItemByUniqueID(int uniqueID) const;
        /*!
        *@brief       获取属性分组数目
        *@return int
        */
        int GetGroupItemsCount() const;
        /*!
        *@brief       移除全部属性分组
        *@return      bool
        */
        bool RemoveAllGroupItems();
        /*!
        *@brief      移除单个属性分组
        *@param [in] int groupIndex
        *@return     bool
        */
        bool RemoveGroupItem(int groupIndex);

    private:
        //全部属性分组
        std::vector<std::unique_ptr<CPropertyGroupItem>>  m_groupItems;
    };

}
#endif // G_PROPERTYINSTANCE_SETTING_H